import java.util.*;

public class DomainLogic {

	private DataBase db;
	private User user;


	public DomainLogic(DataBase db) {
    setDataBase(db);
    setUser(null);

	}

	public void setUser(User newUser) {user = newUser;}
	public User getUser() {return user;}
	public void setDataBase(DataBase database) {db = database;}
	public DataBase getDataBase() {return db;}

	// 1. check if username is found in database
	// 2. if [1], get password from db corresponding to username, and match with the parameter password
	// 3. if [2], create a new LogOn user
	public boolean logOn(String username, String password) {
		User user = db.getUser(username);
		boolean loggedOn = false;
		if (user != null) {
			if (password.equals(user.getPassword())) {
				setUser(user);
				loggedOn = true;
			}
		}
		return loggedOn;
	}

	// log the user off (set the LogOn user to null)
	public void logOff() {setUser(null);}

	// register a new user
  public void registerUser(String username, String password, Preferences prefs) {
    User user = db.getUser(username);
    String message = null;
    if (user == null) {
      String type = "member";
      User newUser = new User(username, password, type);
      newUser.setPreferences(new Vector<UserPreferences>());
      db.addUser(username, newUser);
      setUser(user); // if registered, log the user on
    }
  }
	// find restaurants based on criteria

	public Vector<Restaurant> findRestaurants(String foodType, String zipCode, Preferences pref) {

		//System.out.println(foodType + zipCode + pref);
		// parse the preferences
		Vector<String> cost = pref.getCost();
		Vector<String> meal = pref.getMeal();
		Vector<String> type = pref.getType();
		Vector<String> mood = pref.getMood();

		// search for restaurants by each criteria
		Vector<String> rests_foodType = db.getRestaurantsByFoodType(foodType, zipCode);
		//Vector<String> rests_zipCode = db.getRestaurantsByZip(zipCode);
		Vector<String> rests_cost = db.getRestaurantsByPreferences("cost", foodType, zipCode, cost);
		Vector<String> rests_meal = db.getRestaurantsByPreferences("meal", foodType, zipCode, meal);
		Vector<String> rests_type = db.getRestaurantsByPreferences("type", foodType, zipCode, type);
		Vector<String> rests_mood = db.getRestaurantsByPreferences("mood", foodType, zipCode, mood);
				
		// count occurrences of restaurants from search results
		HashMap occurrences = new HashMap();
		Vector result = null; // vector of <HashMap occurrences, Integer highestCount>

		result = countOccurrences(occurrences, rests_foodType, null);
		//result = countOccurrences((HashMap)(result.elementAt(0)), rests_zipCode);
		result = countOccurrences((HashMap)(result.elementAt(0)), rests_cost, ((Integer)(result.elementAt(1))));
		//System.out.println(result);
		result = countOccurrences((HashMap)(result.elementAt(0)), rests_meal, ((Integer)(result.elementAt(1))));
		result = countOccurrences((HashMap)(result.elementAt(0)), rests_type, ((Integer)(result.elementAt(1))));
		result = countOccurrences((HashMap)(result.elementAt(0)), rests_mood, ((Integer)(result.elementAt(1))));
		occurrences = (HashMap)(result.elementAt(0));
		int highestCount = ((Integer)(result.elementAt(1))).intValue();
		Vector<Restaurant> restaurants = new Vector();

		int count = 0;
		//System.out.println(highestCount);
		// get restaurants by descending order of counts
		for (int i=highestCount; i > 0; i--) {
			// loop through occurrences
			for (String restName : ((HashMap<String,Object>) occurrences).keySet()) {
				count = ((Integer)(occurrences.get(restName))).intValue();
				// add restaurant if its count matches current decremented highestCount
				if (count == highestCount && !restaurants.contains(db.getRestaurant(restName)) ) {
					restaurants.addElement(db.getRestaurant(restName));
					//System.out.println("adding ");
				}
			}
		}

		return restaurants;
	}

	// count up occurrences of restaurants
	public Vector countOccurrences(HashMap occurrences, Vector<String> restaurants, Integer inCount) {
		String restName = null;
		Vector result = new Vector();
		int count = 0;
		int highestCount = 0;
		if (inCount != null) {highestCount = inCount.intValue();}

    if (inCount != null) {highestCount = inCount.intValue();}
		
		for (int i=0; i < restaurants.size(); i++) {
			restName = restaurants.elementAt(i);
			if (occurrences.containsKey(restName)) {
				count = ((Integer)(occurrences.get(restName))).intValue() + 1;
				occurrences.put(restName, new Integer(count));
				
				//System.out.println("contains: "+restName);
			}
			else {
				occurrences.put(restName, new Integer(1));
				count = 1;
				//System.out.println("not contains: "+restName);
			}
			if (count > highestCount) {highestCount = count;} // update highest count
		}
		//System.out.println(highestCount);
		result.addElement(occurrences); // add the hashmap of occurrences
		result.addElement(new Integer(highestCount)); // add the highest count
		return result;
	}

	
	// add preferences to the user profile

	public void addUserPreferences(UserPreferences prefs) {
		User user = getUser();
		db.addUserPreferences(user.getUsername(), prefs);
	}

	// gets preferences from the user profile
	public Vector<UserPreferences> getUserPreferences() {
		User user = getUser();
    return user.getPreferences();
	}

	
	public Vector<Restaurant> sortResults(Vector<Restaurant> restaurantVector, String opt1, String opt2){
		
		Vector<Restaurant>sortedList = new Vector<Restaurant>();

		Comparator<Restaurant> mycomp;
		//sort by cost
		if(opt1.equals("C")){
			mycomp = new CostComparator();
		}
		else{
			mycomp = new RatingComparator();
		}
			
		PriorityQueue<Restaurant> sortedQueue = new PriorityQueue<Restaurant>(
														restaurantVector.size(),
														mycomp);			
		for(int i =0; i < restaurantVector.size(); i++){
			sortedQueue.add(restaurantVector.get(i));
		}
		//System.out.println(sortedQueue);
		if(opt2.equals("a")){
		    while(sortedQueue.size() > 0  ){
		    	//sortedQueue.peek().setAddress(sortedQueue.peek().getAddress() + " "+ sortedQueue.peek().getPreferences().getCost().get(0));
				sortedList.add(sortedQueue.poll());
			}
		}
		else{
		    while(sortedQueue.size() > 0  ){
		    	//sortedQueue.peek().setAddress(sortedQueue.peek().getAddress() + " "+ sortedQueue.peek().getPreferences().getCost().get(0));
				sortedList.add(0,sortedQueue.poll());
			}
		}					
		return sortedList;
	}
	
  // returns the Restaurant object named <restName>
  public Restaurant getRestaurant(String restName) {
    return db.getRestaurant(restName);
  }

  // adds a restaurant to the database
  public void addRestaurant(String restName, String address, String zipCode, String foodType, Preferences prefs) {
    Restaurant restaurant = new Restaurant(restName, address, zipCode, foodType, prefs);
    db.addRestaurant(restName, restaurant);
  }

  // changes some fields in a restaurant object
  public void editRestaurant(String restName, String address, String zipCode, String foodType, Preferences prefs) {
    Restaurant restaurant = db.getRestaurant(restName);
    restaurant.setName(restName);
    restaurant.setAddress(address);
    restaurant.setZipCode(zipCode);
    restaurant.setFoodType(foodType);
    restaurant.setPreferences(prefs);
    db.addRestaurant(restName, restaurant); // replaces the old restaurant in the database by this updated restaurant
  }

  // deletes the restaurant of name <name> from the database
  public void deleteRestaurant(String restName) {
    db.deleteRestaurant(restName);
  }

  // returns a Vector of restaurant names
  public Vector<String> showRestaurantNames() {
    Vector<String> names = db.getRestaurantsByName();
    return names;
  }

  // adds a rating to a restaurant
  public void rateRestaurant(String restName, double rating) {
    Restaurant restaurant = db.getRestaurant(restName);
    restaurant.addRating(rating);
    db.addRestaurant(restName, restaurant); // replaces the old restaurant in the database by this updated restaurant
  }
}


class CostComparator implements Comparator<Restaurant> {
	int ob1;
	int ob2;
	@Override
	public int compare(Restaurant o1, Restaurant o2) {
		//System.out.println("ob1 = " + o1.getPreferences().getCost().get(0) + " obj2 = " + o2.getPreferences().getCost().get(0));
		if( o1.getPreferences().getCost().get(0).substring(0,1).equals("c") 
				&& o2.getPreferences().getCost().get(0).substring(0,1).equals("a")){
			return -1;
		}

		else if( o1.getPreferences().getCost().get(0).substring(0,1).equals("c") 
				&& o2.getPreferences().getCost().get(0).substring(0,1).equals("e")){
			return -1;
		}	
		
		else if( o1.getPreferences().getCost().get(0).substring(0,1).equals("a") 
				&& o2.getPreferences().getCost().get(0).substring(0,1).equals("e")){
			return -1;
		}
		
		else if( o1.getPreferences().getCost().get(0).substring(0,1).equals("a") 
				&& o2.getPreferences().getCost().get(0).substring(0,1).equals("c")){
			return 1;
		}		
		
		else if( o1.getPreferences().getCost().get(0).substring(0,1).equals("e") 
				&& o2.getPreferences().getCost().get(0).substring(0,1).equals("c")){
			return 1;
		}		
		
		else if( o1.getPreferences().getCost().get(0).substring(0,1).equals("e") 
				&& o2.getPreferences().getCost().get(0).substring(0,1).equals("a")){
			return 1;
		}		
		
		else
			return 0;
	}
}

class RatingComparator implements Comparator<Restaurant> {

	@Override
	public int compare(Restaurant o1, Restaurant o2) {
		if(o1.getRating() < o2.getRating() ){
			return -1;
		}
		else if(o1.getRating() > o2.getRating() ){
			return 1;
		}
		else{
			return 0;
		}
	}
}
